package com.yhy.tradesystem;

import java.util.ArrayList;
import java.util.Date;

import com.yhy.tradesystem.TradeDataPak.BuySellSignal;
import com.yhy.tradesystem.util.Log;

public class PositionMoneyController implements TradeSystemFilter{
	
	protected ArrayList<TradeSystemFilter> outputFilter = new ArrayList<TradeSystemFilter>();
	protected TradeDataPak pak;
	private String NAME="仓位与资金管理";
	
	private float money= 1000000;
	
	/**最小交易量*/
	private int TradeLimit = 100;
	
	public static class MoneyRecord{
		public MoneyRecord(Date date, float diff, float after) {
			super();
			this.date = date;
			this.diff = diff;
			this.after = after;
		}
		public final Date date;
		@Override
		public String toString() {
			return String.format("时间 %s,变化金额 %.2f,变化后总额 %.02f\n", date.toGMTString(),diff,after);
		}
		public final float diff;
		public final float after;
	}
	
	ArrayList<MoneyRecord> moneyRecord = new ArrayList<PositionMoneyController.MoneyRecord>();
	
	public static class ActivityTradeInfo{
		/**股票名称*/
		public String stockName;
		/**仓位*/
		public int position;
		/**成本价*/
		public float cost;
		/**最新价*/
		public float newPrice;
		/**最新价时间*/
		public Date newPriceDate;
		/**交易类型*/
		public TradeDataPak.BuySellSignal.BuySellType type;
		@Override
		public String toString() {
			return String.format("%s 成本%f 数量%d 最新价格 %f", stockName,cost,position,newPrice);
		}
		
		
	}
	ArrayList<ActivityTradeInfo> activityTrade = new ArrayList<ActivityTradeInfo>();
	ArrayList<TradeDataPak.BuySellSignal> historyTrade = new ArrayList<TradeDataPak.BuySellSignal>();
	
	/**成功交易与失败交易次数*/
	private int winTime=0;
	private int lostime=0;
	
	/**
	 * 存入或取出指定数量的现金
	 * */
	public float changeMoney(float diff){
		money+=diff;
		moneyRecord.add(new MoneyRecord(pak.stockData.date, diff, money));
		return money;
	}
	
	public float getCurrentMoney(){
		return money;
	}
	@Override
	public void connectOutput(TradeSystemFilter filter) {
		if(filter!=null){
			outputFilter.add(filter);
		}
	}

	private void updatePriceData(TradeDataPak data){
		for(ActivityTradeInfo info:activityTrade){
			if(info.stockName.equals(data.stockData.stockName)){
				info.newPrice = data.stockData.close;
				info.newPriceDate = data.stockData.date;
			}
		}
	}
	@Override
	public void inputData(TradeDataPak data) {
		this.pak = data;
		updatePriceData(data);
		if(pak.signal!=null){
			pak.signal = doBuySell(data);
			outputData();
		}
	}
	
	public void dumpReport(){
		Log.d(NAME, "当前持仓情况");
		for(ActivityTradeInfo info:activityTrade){
			Log.d(NAME,info.toString());
		}
		Log.d(NAME, "资金余额 %f",money);
		Log.d(NAME, "成功的交易 %d 失败的交易 %d", winTime,lostime);
	}
	
	public String dumpMoneyChangeHistory(){
		StringBuilder builder=new StringBuilder();
		builder.append("资金变化报告\n");
		for(MoneyRecord rec:moneyRecord){
			builder.append(rec.toString());
		}
		return builder.toString();
	}
	
	//计算交易手续费
	private float calcTradeFee(float money){
		return money * 0.5f/10000.0f;
	}

	/**
	 * 用最新价格强制平仓
	 * */
	public void forceCloseAllTrade(){
		for(ActivityTradeInfo info:activityTrade){
			if(info.type == TradeDataPak.BuySellSignal.BuySellType.BuySellOpen){
				changeMoney(info.position * info.newPrice);
				Log.d(NAME, "强制平仓 %f 数量%d", info.newPrice,info.position);
			}
			//TODO:平空仓
		}
		
	}
	private BuySellSignal doBuySell(TradeDataPak data) {
		//FIXME:最简单的仓位管理策略 一次买入全部/没有设计做空的情况
		
		BuySellSignal signal = data.signal;
		BuySellSignal outputSignal = null;
		
		if(signal.type == TradeDataPak.BuySellSignal.BuySellType.BuySellOpen){
			//买入做多
			for(ActivityTradeInfo info:activityTrade){
				if(info.type.equals(signal.type) && info.stockName.equals(signal.stockName)){
					int position = (int) (money / signal.price);
					if(position>TradeLimit){
						//已经有正在进行的交易，合并
						float moneySpent = position*signal.price;
						moneySpent+=calcTradeFee(moneySpent);
						changeMoney(-moneySpent);
						info.position += position;
						info.cost = (info.cost + moneySpent)/(float)info.position;
						
						outputSignal = new BuySellSignal(signal.stockName, position, signal.type, signal.price);
						
						Log.d(NAME, "买入数量%d，%s在%f", position,signal.stockName,signal.price);
					}else{
						Log.d(NAME, "资金太少%f，放弃%s在%f价位的交易", money,signal.stockName,signal.price);
					}
					
					break;
				}
			}
			
			if(outputSignal == null){
				//该股票没有持仓，新开一个交易
				int position = (int) (money / signal.price);
				if(position>TradeLimit){
					outputSignal = new BuySellSignal(signal.stockName, position, signal.type, signal.price);
					ActivityTradeInfo info =new ActivityTradeInfo();
					info.stockName = signal.stockName;
					info.position = position;
					info.type = signal.type;
					activityTrade.add(info);
					
					float moneySpent = position*signal.price;
					moneySpent+=calcTradeFee(moneySpent);
					info.cost = moneySpent/position;
					changeMoney(-moneySpent);
					
					Log.d(NAME, "买入数量%d，%s在%f", position,signal.stockName,signal.price);
				}else{
					Log.d(NAME, "资金太少%f，放弃%s在%f价位的交易", money,signal.stockName,signal.price);
				}
			}
		}
		
		if(signal.type == TradeDataPak.BuySellSignal.BuySellType.BuySellClose){
			//做多平仓
			for(ActivityTradeInfo info:activityTrade){
				if(info.stockName.equals(signal.stockName)){
					int position = info.position;
					if(position>TradeLimit){
						float moneyGet = position*signal.price;
						moneyGet -= calcTradeFee(moneyGet);
						float moneySpent = info.cost * info.position;
						changeMoney(moneyGet);
						activityTrade.remove(info);
						Log.d(NAME, "卖出数量%d，%s在 %f -> %f 获利%f 获利百分比%f", position,signal.stockName,info.cost,signal.price,(moneyGet - moneySpent),(moneyGet - moneySpent)/moneySpent * 100.0f);
						outputSignal = new BuySellSignal(signal.stockName, position, signal.type, signal.price);
						
						if(signal.price > info.cost){
							winTime++;
						}else{
							lostime++;
						}
						
						dumpReport();
					}else{
						Log.d(NAME, "交易数量太低%d，放弃%s在%f价位的交易", position,signal.stockName,signal.price);
					}
					
					break;
				}
			}
			if(outputSignal == null){
				Log.e(NAME,signal.stockName+"交易不存在，无法卖出"); 
			}
			
		}
		if(outputSignal!=null){
			historyTrade.add(outputSignal);
		}
		return outputSignal;
	}

	@Override
	public TradeDataPak outputData() {
		for(TradeSystemFilter filter:outputFilter){
			filter.inputData(pak);
		}
		return pak;
	}

	@Override
	public String getName() {
		return NAME;
	}

	@Override
	public void resetData() {
		moneyRecord.clear();
		historyTrade.clear();
		money = 0.0f;
		winTime = lostime =0;
	}

}
